package com.cloudlinkscm.base.authcenter.domain;

import com.cloudlinkscm.base.authcenter.constant.RoleStatusEnum;
import com.cloudlinkscm.base.authcenter.dao.RoleDao;
import com.cloudlinkscm.base.authcenter.dao.RolePermissionRelationDao;
import com.cloudlinkscm.base.authcenter.dao.TenantResourceDao;
import com.cloudlinkscm.base.authcenter.model.Resource;
import com.cloudlinkscm.base.authcenter.model.Role;
import com.cloudlinkscm.base.authcenter.model.RolePermissionRelation;
import com.cloudlinkscm.base.authcenter.model.TenantResource;
import com.cloudlinkscm.base.authcenter.model.bo.NodeAllResourceBO;
import com.cloudlinkscm.base.authcenter.model.dto.ResourceTree;
import com.cloudlinkscm.base.authcenter.model.dto.TenantRoleSaveDTO;
import com.cloudlinkscm.base.authcenter.model.dto.TenantRoleUpdateDTO;
import com.cloudlinkscm.loms.utils.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by sin on 2017/8/8.
 *
 * 角色 manager
 */
@Service
public class RoleManager {

	@Autowired
	private RoleDao roleDao;
	@Autowired
	private RolePermissionRelationDao relationDao;
	@Autowired
	private TenantResourceDao tenantResourceDao;
	@Autowired
	private ResourceManager resourceManager;


	/**
	 * 角色：保存
	 *
	 * @param saveDTO
	 * @return
	 */
	public Role save(TenantRoleSaveDTO saveDTO) {

		Role role = new Role();
		BeanUtils.copyProperties(saveDTO, role);
		role.setStatus(RoleStatusEnum.STATUS_NOT_ACTIVE.code);
		roleDao.insert(role);

		return role;
	}


	/**
	 * 角色：更新
	 *
	 * @param updateDTO
	 * @return
	 */
	public int update(TenantRoleUpdateDTO updateDTO) {
		Role role = new Role();
		BeanUtils.copyProperties(updateDTO, role);
		return roleDao.updateByPrimaryKeySelective(role);
	}


	/**
	 * 角色：激活
	 *
	 * @param id
	 * @return
	 */
	public int active(String id) {

		Role role = new Role();
		role.setId(id);
		role.setStatus(RoleStatusEnum.STATUS_ACTIVE.code);

		return roleDao.updateByPrimaryKeySelective(role);
	}

	/**
	 * 角色：失效
	 *
	 * @param id
	 * @return
	 */
	public int invalid(String id) {
		Role role = new Role();
		role.setId(id);
		role.setStatus(RoleStatusEnum.STATUS_DISABLE.code);

		return roleDao.updateByPrimaryKeySelective(role);
	}


	/**
	 * 角色关系：添加
	 *
	 * @param roleId
	 * @param tenantResourceIds
	 * @param tenantId
	 * @return
	 */
	public int roleRelationAdd(String roleId, List<String> tenantResourceIds, String tenantId) {

		int result = 0;

		// position 引入节点的 上下节点
		List<NodeAllResourceBO> positionNodes = resourceManager.positionNodes(
				resourceManager.convertResource(tenantResourceDao.selectAll()),
				resourceManager.convertResource(tenantResourceDao.selectByIds(tenantResourceIds)));


		// 开始迭代每个 节点的上下节点
		for (NodeAllResourceBO positionResource : positionNodes) {
			List<Resource> resources = positionResource.getDistributionResource();

			Map<String, RolePermissionRelation> relationMap = Collections.EMPTY_MAP;
			if (!org.springframework.util.CollectionUtils.isEmpty(resources)) {

				// 判断 relation 是否存在 节点 TODO 需要抽离 一次性获取，在外构建结构
				List<RolePermissionRelation> relationList =
						relationDao.selectByRoleIdAndResourceIds(roleId, CollectionUtils.buildSet(
								resources, String.class, "id"));

				if (!org.springframework.util.CollectionUtils.isEmpty(relationList)) {
					relationMap = CollectionUtils.buildMap(
							relationList, String.class, RolePermissionRelation.class, "resourceId");
				}
			}

			for (Resource resource : resources) {

				// 判断 relation 是否存在 resource
				if (!relationMap.containsKey(resource.getId())) {
					RolePermissionRelation relation = new RolePermissionRelation();
					relation.setRoleId(roleId);
					relation.setResourceId(resource.getId());
					relation.setTenantId(tenantId);
					result += relationDao.insert(relation);
				}
			}
		}
		return result;
	}


	/**
	 * 角色关系：remove
	 *
	 * @param resourceIds 需要删除的 resourceId
	 * @return 删除的条数
	 */
	public int roleRelationRemove(Collection<String> resourceIds) {

		// 构建数据
		List<TenantResource> allTenantResources = tenantResourceDao.selectAll();
		List<TenantResource> removeResources = tenantResourceDao.selectByIds(resourceIds);

		List<RolePermissionRelation> relationList = relationDao.selectAll();
		List<TenantResource> relationResources = tenantResourceDao.selectByIds(
				CollectionUtils.buildSet(relationList, String.class, "resourceId"));

		Map<String, List<TenantResource>> parentRelationMultimap = CollectionUtils.buildMultimap(
				relationResources, String.class, TenantResource.class, "pid");


		// build 租户的整个树结构
		List<ResourceTree> tenantTrees = resourceManager.buildResourceTree(
				resourceManager.convertResource(allTenantResources));

		// position 所有需要删除的节点，上下结构
		List<NodeAllResourceBO> positionNodes = resourceManager.positionNodes(
				resourceManager.convertResource(allTenantResources),
				resourceManager.convertResource(removeResources));

		// 抽取 position 所有节点的 resourceKeys 方便递归使用
		List<Resource> positionAllResources = new ArrayList<>();
		for (NodeAllResourceBO<Resource> positionNode : positionNodes) {
			positionAllResources.addAll(positionNode.getDistributionResource());
		}

		Set<String> positionResourceKeys = CollectionUtils.buildSet(
				positionAllResources, String.class, "resourceKey");

		// 开始删除
		Set<String> ids = recursionRemoveTreeNode(tenantTrees, positionResourceKeys, parentRelationMultimap);
		return relationDao.deleteByIds(ids);
	}


	/**
	 * 角色关系：递归删除
	 *
	 * @param tenantTress 租户的整个 resource
	 * @param positionResourceKeys 需要删除的 resourceKeys
	 * @param parentRelationMultimap 每个节点的子节点
	 * @return 需要删除的节点 id
	 */
	private Set<String> recursionRemoveTreeNode(List<ResourceTree> tenantTress,
	                                            Set<String> positionResourceKeys,
	                                            Map<String, List<TenantResource>> parentRelationMultimap) {

		// 每一级删除的 resourceId，只要 parent 节点下存在任意一个未删除节点，保留 parent 节点
		Set<String> removeIds = new HashSet<>();
		for (ResourceTree<Resource> resourceTree : tenantTress) {

			// 存在 children 节点直接递归，到最底层节点，从下往上
			if (!org.springframework.util.CollectionUtils.isEmpty(resourceTree.getChildren())) {
				Set<String> childrenRemoveIds = recursionRemoveTreeNode(resourceTree.getChildren(), positionResourceKeys, parentRelationMultimap);

				// 只要节点大于 0 添加删除节点
				if (childrenRemoveIds.size() > 0) {
					removeIds.addAll(childrenRemoveIds);
				}

				// 是否保留 parent 节点
				if (parentRelationMultimap.containsKey(resourceTree.getData().getId())) {

					// 抽取 当前节点的 children 节点
					Set<String> findChildren = new HashSet<>();
					for (TenantResource tenantResource : parentRelationMultimap.get(resourceTree.getData().getId())) {
						if (childrenRemoveIds.contains(tenantResource.getId())) {
							findChildren.add(tenantResource.getId());
						}
					}

					// 当前节点存在任意节点保留 parent 节点
					if (findChildren.size() >= parentRelationMultimap.get(resourceTree.getData().getId()).size()) {
						// 没有了，当前 parent 节点可以删除了
						removeIds.add(resourceTree.getData().getId());
					}
				}
			}
			else {

				// 是否删除节点
				if (positionResourceKeys.contains(resourceTree.getData().getResourceKey())) {
					removeIds.add(resourceTree.getData().getId());
				}
			}
		}

		return removeIds;
	}


	/**
	 * 角色关系：构建一棵树
	 *
	 * <p>
	 *     返回一个 {@link RoleRelationTreeVO}，distribution 已分配完的资源
	 *
	 *     notDistribution 未分配资源
	 * </p>
	 *
	 * @param roleId 角色 id
	 * @return 构建两棵树
	 */
	public RoleRelationTreeVO tree(String roleId) {

		List<RolePermissionRelation> relationList = relationDao.selectByRoleId(roleId);
		List<TenantResource> distributionResources = Collections.EMPTY_LIST;
		Map<String, TenantResource> tenantResourceMap = Collections.EMPTY_MAP;
		if (!org.springframework.util.CollectionUtils.isEmpty(relationList)) {
			// not empty

			Set<String> resourceIds = CollectionUtils.buildSet(relationList, String.class, "resourceId");
			distributionResources = tenantResourceDao.selectByIds(resourceIds);

			if (!org.springframework.util.CollectionUtils.isEmpty(distributionResources)) {
				tenantResourceMap = com.cloudlinkscm.loms.utils.CollectionUtils.buildMap(
						distributionResources, String.class, TenantResource.class, "resourceKey");
			}
		}

		List<ResourceTree> resourceTrees = resourceManager.buildResourceTree(
				resourceManager.convertResource(tenantResourceDao.selectAll()));

		Set<Resource> repeatResource = new HashSet<>(resourceManager.buildNewResource(resourceTrees, tenantResourceMap));

		// 构建返回
		return new RoleRelationTreeVO(
				resourceManager.buildResourceTree(resourceManager.convertResource(new ArrayList<>(repeatResource))),
				resourceManager.buildResourceTree(resourceManager.convertResource(distributionResources)));
	}
}
